package ipgather.core.ip;

import java.io.IOException;
import java.lang.reflect.Executable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.http.Consts;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import ipgather.constant.PortConstant;
import ipgather.core.proxy.thread.ProxyCheck;
import ipgather.core.redis.RedisDbAdapter;
import ipgather.entity.Host;
import ipgather.util.IpUtil;

public class IpMatch {

	private CloseableHttpClient httpClient;
	
	public IpMatch(){}
	public IpMatch(CloseableHttpClient httpClient){
		this.httpClient = httpClient;
	}
	public Set<String> findIpsByRequest(HttpGet[] requests){
		List<HttpGet> reqs = new ArrayList<>();
		for(HttpGet request : requests){
			reqs.add(request);
		}
		return findIpsByRequest(reqs);
	}
	public Set<String> findIpsByRequest(String[] requests){
		List<HttpGet> reqs = new ArrayList<>();
		for(String url : requests){
			reqs.add(new HttpGet(url));
		}
		return findIpsByRequest(reqs);
	}
	public Set<String> findIpsByRequest(List<HttpGet> requests){
		Set<String> s = new HashSet<>();
		int nThread = Runtime.getRuntime().availableProcessors();//获取CPU个数
		int size = requests.size();
		int blockSize = (size+nThread) / nThread;
		ExecutorService es = Executors.newFixedThreadPool(nThread);
		List<Future<Set<String>>> result = new ArrayList<>();
		for(int i =0;i<nThread;i++){
			final int min = i * blockSize;
			final int max = Math.min(min+blockSize, size);
			final List<HttpGet> request = requests.subList(min, max);
			result.add(es.submit(new Callable<Set<String>>() {
				@Override
				public Set<String> call() throws Exception {
					return findIpsByRequestByThread(request);
				}
			}));
		}
		es.shutdown();
		for(Future<Set<String>> future : result){
			try {
				s.addAll(future.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		return s;
	}
	
	private Set<String> findIpsByRequestByThread(List<HttpGet> requests){
		Set<String> ips = new HashSet<>(0);
		for(HttpGet request : requests){
			ips.addAll(findIpsByRequest(request));
		}
		return ips;
	}
	
	public Set<String> findIpsByRequest(HttpGet request){
		if(null==httpClient){
			httpClient = HttpClients.createDefault();
		}
		Set<String> ips = new HashSet<>();
		CloseableHttpResponse response = null;
		try {
			System.out.println("抓取地址："+request.getURI());
			response = httpClient.execute(request);
			ips = IpUtil.findIps(EntityUtils.toString(response.getEntity(),Consts.UTF_8));
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return ips;
	}
	
	public void validatorEnableIps(Set<String> ips){
		if(null==httpClient){
			httpClient = HttpClients.createDefault();
		}
		RedisDbAdapter redisDbAdapter = RedisDbAdapter.create();
		for(String host : ips){
			new Thread(new Runnable() {
				public void run() {
					for (int port : PortConstant.PORTS) {//搜索常用服务器http端口
						if(new ProxyCheck(httpClient).checkProxyHost(new Host(host, port))){
							System.out.println("\n验证成功："+host+":"+port);
							if(redisDbAdapter.hostExist(new Host(host, port))){
								System.out.println("\nDB中已存在："+host+":"+port);
							}else{
								System.err.println("\n保存到redis："+host+":"+port);
								redisDbAdapter.saveHost(host, port);// 保存到redis数据库
							}
						}else{
							System.out.print("*");
						}
					}
				}
			}).start();
		}
	}
}
